<?php
/**
 * Created by PhpStorm.
 * User: guokunsheng
 * Date: 2020/11/18
 * Time: 15:02
 */

namespace App\Tools\Astrolog;

/**
 * Class LogicBase
 * @package app\common\lib\astrolog
 */
class LogicBase
{
    /**
     * 行星落座
     * @param array $data 行星数据 'planets'
     * @param int $pid
     * @param int|array $sign
     * @return bool
     */
    protected function isPlanetInSign($data, $pid, $sign)
    {
        if (is_array($sign))
        {
            return in_array($data[$pid]['in_sign_id'], $sign, true);
        }
        return $data[$pid]['in_sign_id'] === $sign;
    }

    /**
     * 行星是否落入某宫
     * @param $data array 行星数据 'planets'
     * @param $planet int 星体ID
     * @param $house array|int 宫位数组
     * @return boolean
     */
    protected function isPlanetInHouse($data, $planet, $house): bool
    {
        if (empty($data) || !isset($data[$planet]) || $planet < 0 || $planet > 20 || empty($house))
        {
            return false;
        }
        if (is_int($house))
        {
            return $data[$planet]['in_house_id'] === $house;
        }
        return in_array($data[$planet]['in_house_id'], $house, false);
    }

    /**
     * 行星1与行星2是否成相
     * @param $data array 行星数据
     * @param $pid1 int 星体1id 如：3
     * @param $pid2 int 星体2id 如：4
     * @param $phase array 相位度数数组  如：[90,180]
     * @return boolean
     */
    protected function isPlanetPhasePlanet($data, $pid1, $pid2, $phase): bool
    {
        $key = $pid1 . '-' . $pid2;
        if ($pid1 < 0 || $pid1 > 20 || $pid2 < 0 || $pid2 > 20 || empty($data) || empty($phase) || !isset($data[$pid1]['phase'][$key]))
        {
            return false;
        }
        return in_array($data[$pid1]['phase'][$key]['phase_e'], $phase, false);
    }

    /**
     * 检测星体1是否互容接纳星体2
     * @param $data array 星盘特征数据 'characteristic'
     * @param $pid1 int 星体1
     * @param $pid2 int 星体2
     * @param $type int[] 需要检测的类型
     * @return boolean
     */
    protected function isPlanetReceptOrMutualReceptPlanet($data, $pid1, $pid2, $type = [1, 2]): bool
    {
        if (!empty($data))
        {
            foreach ($data as $k1 => $v1)
            {
                if (in_array($k1, $type, false))
                {
                    foreach ($v1 as $v2)
                    {
                        if (((int)$pid1 === (int)$v2['id1'] && (int)$pid2 === (int)$v2['id2'])
                            || ((int)$pid2 === (int)$v2['id1'] && (int)$pid1 === (int)$v2['id2']))
                        {
                            return true;
                        }
                    }
                }

            }
        }
        return false;
    }

    /**
     * 使变量保持在 min与max之间 含前不含后
     * @param $var
     * @param int $min 0        1
     * @param int $max 360      13
     * @return float
     */
    protected function mod($var, $min = 0, $max = 360)
    {
        $diff = $max - $min;
        if ($var >= $max)
        {
            $var -= floor($var / $diff) * $diff;
        } elseif ($var < $min)
        {
            if ($var == 0)
            {
                $var = $max - 1;
            } else
            {
                $var -= floor($var / $diff) * $diff;
            }
        }
        return $var;
    }

    /**
     * 检测是否群星落座
     * @param $data array 星体数据
     * @param $sign int 星座ID
     * @param int[] $planets 需要检测的星体ID数组
     * @return bool
     */
    protected function isMutiplePlanetInSign($data, $sign, $planets = [0, 1, 2, 3, 4, 5, 6]): bool
    {
        $num = 0;
        foreach ($planets as $p)
        {
            if ($this->isPlanetInSign($data, $p, $sign))
            {
                $num++;
            }
        }
        return $num >= 3;
    }

    /**
     * 检测是否群星落宫
     * @param array $data 星体数据
     * @param array $house 宫位ID
     * @param int[] $planets 需要检测的星体ID数组
     * @return bool
     */
    protected function isMutiplePlanetInHouse($data, $house, $planets = [0, 1, 2, 3, 4, 5, 6]): bool
    {
        $num = 0;
        foreach ($planets as $p)
        {
            if ($this->isPlanetInHouse($data, $p, $house))
            {
                $num++;
            }
        }
        return $num >= 3;
    }

    /**
     * 宫主星落座
     * @param $data
     * @param $hid
     * @param $sign
     * @return bool
     */
    protected function isHouseProtectInSign($data, $hid, $sign): bool
    {
//        return $this->isPlanetInSign($data['planets'], $data['houses'][$hid]['protect_ancient_id'], $sign);
        return $data['houses'][$hid]['protect_ancient_insign_id'] === $sign;
    }

    /**
     * 宫主星落宫位
     * @param $data
     * @param $hid
     * @param $house
     * @return bool
     */
    protected function isHouseProtectInHouse($data, $hid, $house): bool
    {
//        return $this->isPlanetInHouse($data['planets'], $data['houses'][$hid]['protect_ancient_id'], $house);
        return $data['houses'][$hid]['protect_ancient_inhouse_id'] === $house;
    }

    /**
     * 宫主星成相
     * @param array $data 星盘数据
     * @param $hid
     * @param $pid
     * @param $phase
     * @return bool
     */
    protected function isHouseProtectPhasePlanet($data, $hid, $pid, $phase)
    {
        $pid1 = $data['houses'][$hid]['protect_ancient_id'];
        return $this->isPlanetPhasePlanet($data['planets'], $pid1, $pid, $phase);
    }

    /**
     * 宫主星互容接纳行星
     * @param $data
     * @param $hid
     * @param $pid
     * @param int[] $type
     * @return bool
     */
    protected function isHouseProtectReceptOrMutualReceptPlanet($data, $hid, $pid, $type = [1, 2])
    {
        $pid1 = $data['houses'][$hid]['protect_ancient_id'];
        return $this->isPlanetReceptOrMutualReceptPlanet($data['characteristic'], $pid1, $pid, $type);
    }

    /**
     * 宫主星互容接纳宫主星
     * @param $data
     * @param $hid1
     * @param $hid2
     * @param int[] $type
     * @return bool
     */
    protected function isHouseProtectReceptOrMutualReceptHouseProtect($data, $hid1, $hid2, $type = [1, 2])
    {
        $pid1 = $data['houses'][$hid1]['protect_ancient_id'];
        $pid2 = $data['houses'][$hid2]['protect_ancient_id'];
        return $this->isPlanetReceptOrMutualReceptPlanet($data['characteristic'], $pid1, $pid2, $type);
    }

    /**
     * 宫头落座
     * @param array $data 宫位数据 'houses'
     * @param int $hid 宫位ID
     * @param int $sign 星座ID
     * @return bool
     */
    protected function isHouseSign($data, $hid, $sign): bool
    {
        return $data[$hid]['in_sign_id'] === $sign;
    }

    /**
     * 宫主星与宫主星成相
     * @param array $data 行星数据
     * @param int $hid1 宫位ID1
     * @param int $hid2 宫位ID2
     * @param array $phase 相位数组
     * @return bool
     */
    protected function isHouseProtectPhaseHouseProtect($data, $hid1, $hid2, $phase): bool
    {
        $p1 = $data['houses'][$hid1]['protect_ancient_id'];
        $p2 = $data['houses'][$hid2]['protect_ancient_id'];
        return $this->isPlanetPhasePlanet($data['planets'], $p1, $p2, $phase);
    }

    /**
     * 行星是否空相
     * @param $data
     * @param $pid
     * @return bool
     */
    protected function isPlanetEmptyPhase($data, $pid): bool
    {
        if (!empty($data[$pid]['phase']))
        {
            foreach ($data[$pid]['phase'] as $phase)
            {
                if ($phase['id'] <= 9)
                {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 逻辑处理
     * @param int $type 类型
     *  1=>行星落座,2=>行星落宫,3=>宫主星落座,4=>宫主星落宫位,5=>行星成相,
     *  6=>行星互容,7=>行星接纳,8=>庙旺,9=>群星落座,10=>群星落宫,11=>同主（两个宫位）
     *  12=>宫主星成相,13=>宫主星互容行星,14=>宫主星接纳行星,15=>宫头星座,16=>宫主星与宫主星成相
     *  17=>行星落陷,18=>宫主星落陷,19=>宫主星互容宫主星,20=>宫主星接纳宫主星
     *  55=>多条件"且",55=>多条件"或"
     * @param $obj1
     * @param $obj2
     * @param $obj3
     * @return bool
     */
    protected function logic($type, $obj1, $obj2 = null, $obj3 = []): bool
    {
        switch ($type)
        {
            // 1、行星落座 $obj1=>行星ID int | $obj2=>星座ID int
            case 1:
                $val = $this->isPlanetInSign($this->astroData['planets'], $obj1, $obj2);
                break;
            // 2、行星落宫 $obj1=>行星ID int | $obj2=>宫位ID array|int
            case 2:
                $val = $this->isPlanetInHouse($this->astroData['planets'], $obj1, $obj2);
                break;
            // 3、宫主星落座 $obj1=>宫位ID int | $obj2=>星座ID int
            case 3:
                $val = $this->isHouseProtectInSign($this->astroData, $obj1, $obj2);
                break;
            // 4、宫主星落宫位 $obj1=>宫位ID int | $obj2=>宫位ID array|int
            case 4:
                $val = $this->isHouseProtectInHouse($this->astroData, $obj1, $obj2);
                break;
            // 5、行星成相 $obj1=>行星ID int | $obj2=>行星ID int | $obj3=>相位数组 array
            case 5:
                $val = $this->isPlanetPhasePlanet($this->astroData['planets'], $obj1, $obj2, $obj3);
                break;
            // 6、行星互容 $obj1=>行星ID int | $obj2=>行星ID int
            case 6:
                $val = $this->isPlanetReceptOrMutualReceptPlanet($this->astroData['characteristic'], $obj1, $obj2, [2]);
                break;
            // 7、行星接纳 $obj1=>行星ID int | $obj2=>行星ID int
            case 7:
                $val = $this->isPlanetReceptOrMutualReceptPlanet($this->astroData['characteristic'], $obj1, $obj2, [1]);
                break;
            // 8、行星庙旺   $obj1=>行星ID int
            case 8:
                $val = ($this->astroData['planets'][$obj1]['ancient']['walls'] === 1 || $this->astroData['planets'][$obj1]['ancient']['promote'] === 1);
                break;
            // 9、群星落座 $obj1=>星座ID int
            case 9:
                $val = $this->isMutiplePlanetInSign($this->astroData['planets'], $obj1);
                break;
            // 10、群星落宫 $obj1=>宫位ID int
            case 10:
                $val = $this->isMutiplePlanetInHouse($this->astroData['planets'], $obj1);
                break;
            // 11、同主 $obj1=>宫位ID int | $obj2=>宫位ID int
            case 11:
                $val = $this->astroData['houses'][$obj1]['protect_ancient_id'] === $this->astroData['houses'][$obj2]['protect_ancient_id'];
                break;
            // 12、宫主星成相 $obj1=>宫位ID int | $obj2=>行星ID int | $obj3=>相位数组 array
            case 12:
                $val = $this->isHouseProtectPhasePlanet($this->astroData, $obj1, $obj2, $obj3);
                break;
            // 13、宫主星互容行星 $obj1=>宫位ID int | $obj2=>行星ID int
            case 13:
                $val = $this->isHouseProtectReceptOrMutualReceptPlanet($this->astroData, $obj1, $obj2, [2]);
                break;
            // 14、宫主星接纳行星 $obj1=>宫位ID int | $obj2=>行星ID int
            case 14:
                $val = $this->isHouseProtectReceptOrMutualReceptPlanet($this->astroData, $obj1, $obj2, [1]);
                break;
            // 15、宫头星座 $obj1=>宫位ID int | $obj2=>星座ID int
            case 15:
                $val = $this->isHouseSign($this->astroData['houses'], $obj1, $obj2);
                break;
            // 16、宫主星与宫主星成相 $obj1=>宫位ID int | $obj2=>宫位ID int | $obj3=>相位 array
            case 16:
                $val = $this->isHouseProtectPhaseHouseProtect($this->astroData, $obj1, $obj2, $obj3);
                break;
            // 17、行星落陷   $obj1=>行星ID int
            case 17:
                $val = ($this->astroData['planets'][$obj1]['ancient']['walls'] === 2 || $this->astroData['planets'][$obj1]['ancient']['promote'] === 2);
                break;
            // 18、宫主星落陷   $obj1=>宫位ID int
            case 18:
                $t = $this->astroData['houses'][$obj1]['protect_ancient_id'];
                $val = ($this->astroData['planets'][$t]['ancient']['walls'] === 2 || $this->astroData['planets'][$t]['ancient']['promote'] === 2);
                break;
            // 19、宫主星互容宫主星 $obj1=>宫位ID int | $obj2=>宫位ID int
            case 19:
                $val = $this->isHouseProtectReceptOrMutualReceptHouseProtect($this->astroData, $obj1, $obj2, [2]);
                break;
            // 20、宫主星接纳宫主星 $obj1=>宫位ID int | $obj2=>宫位ID int
            case 20:
                $val = $this->isHouseProtectReceptOrMutualReceptHouseProtect($this->astroData, $obj1, $obj2, [1]);
                break;
            // 21、行星空相
            case 21:
                $val = $this->isPlanetEmptyPhase($this->astroData['planets'], $obj1);
                break;
            // 55、多条件"且" $obj3=>多条件的数组，里面必须带res，表示该条件的真假状态
            case 55:
                foreach ($obj3 as $o)
                {
                    if ($this->logic($o['type'], $o['obj1'], $o['obj2'], $o['obj3']) !== $o['res'])
                    {
                        return false;
                    }
                }
                return true;
                break;
            // 56、多条件"或" $obj3=>多条件的数组，里面必须带res，表示该条件的真假状态
            case 56:
                foreach ($obj3 as $o)
                {
                    if ($this->logic($o['type'], $o['obj1'], $o['obj2'], $o['obj3']) === $o['res'])
                    {
                        return true;
                    }
                }
                return false;
                break;
            default:
                $val = false;
                break;
        }
        return $val;
    }

    /**
     * 保持数字长度为两位
     * @param int $num
     * @return string
     */
    protected function modNumLength2($num = 0): string
    {
        return $num <= 9 ? ('0' . $num) : (string)$num;
    }
}
